"""
Some terminology:
RPC = Remote Procedure Call. I actually use this term to refer to remote *class* methods.
ROPC = Remote Object Procedure Call. This means we're calling *object* methods on the server.

TODO:
  -Currently, we can only have one "mode" at a time - default, sqlobject, etc.
   Ideally, each object could have it's own "mode" in ObjectSerializer!!
  -MultiExecute: add calls onto the "stack" and have them all fired at once.
"""

import os
import logging

from pythontojavascript.execute import execute as _execute
from pythontojavascript import ObjectSerializer
from pythontojavascript import ExceptionHandler

CONFIG_OPTIONS = {"mode":["default","sqlobject"],
                  "serverencoding":["jsonHack","json"],
                  "clientencoding":["json"],
                  "include_mochikit":[True,False],
                  "include_dojo":[True,False],
                  "autocompile":[True,False],
                  }

CONFIG = {"mode":"default",
          "serverencoding":"json",
          "clientencoding":"json",
          "include_mochikit":False,
          "include_dojo":True,
          "autocompile":False,  # THIS HASN'T BEEN IMPLEMENTED!
          }
          
def setConfig(option,value):
  values = CONFIG_OPTIONS.get(option)
  assert values is not None,"Invalid configuration option"
  assert value in values,"Invalid setting for option '%s'" % option
  CONFIG[option] = value
  
def setBaseURL(url):
  CONFIG['base_url'] = "BASE_URL = %s" % url
  
def setLogger(ext_logger):
  global logger
  logger = ext_logger
  ObjectSerializer.logger = logger
  ExceptionHandler.logger = logger
  
def execute(**args):
  args = decode(args)
  logger.debug("'execute' called with arguments:"+unicode(args))
  try:
    results = _execute(**args)
    logger.debug("'execute' results: "+unicode(results))
    encoded_results = encode(results)
    logger.debug("'execute' encoded_results: "+encoded_results)
  except Exception,e:
    logger.exception("Exception in 'execute':")
    results = ExceptionHandler.packageException()
    encoded_results = encode(results)
  return encoded_results
  
def encode(objects):
  try:
    mod = __import__("pythontojavascript.serverencoders."+
                      CONFIG['serverencoding'],[],[],[CONFIG['serverencoding']])
    logger.debug("Imported encoding module: %s" % CONFIG['serverencoding'])
  except ImportError:
    # Do something here
    raise
  return mod.encode(objects)
  
def decode(args):
  try:
    mod = __import__("pythontojavascript.serverdecoders."+
                      CONFIG['clientencoding'],[],[],[CONFIG['clientencoding']])
    logger.debug("Imported decoding module: %s" % CONFIG['clientencoding'])
  except ImportError:
    # Do something here
    raise
  decoded_results = mod.decode(args)
  return decoded_results
  
def compile():
  # Before we can compile, some base conditions must be set.
  #assert CONFIG.get('base_url'),"You must call setBaseURL before compiling."
  #output = [CONFIG.get('base_url')]
  output = []
  # We need to import other JS files for the output.
  path = os.path.dirname(__file__)
  files = ["misc.js","RPC.js","PythonObject.js"]
  if CONFIG.get("include_dojo"):
    files.append("dojo.js")
  if CONFIG.get("include_mochikit"):
    files.append("mochikit.js")
  # TODO(dobromirv): throw a useful error here
  for f in files:
    tmp =  open(path + "/javascript/" + f)
    contents = tmp.read()
    tmp.close()
    output.append(contents)
  # Now include our clientDecoder + clientEncoder
  decoder = open(path + "/clientdecoders/" + CONFIG["serverencoding"] +
                 ".js").read()
  output.append(decoder)
  encoder = open(path + "/clientencoders/" + CONFIG["clientencoding"] +
                 ".js").read()
  output.append(encoder)

  # Now include our compiled objects
  objects = ObjectSerializer.compile(CONFIG['mode'])
  output.append(objects)
    
  return "\n".join(output)
  
# Things we run when this module is finally loaded.
setLogger(logging)
